#include "stdafx.h"
#include "BuildingController.h"
#include <ISceneCollisionManager.h>
#include "DxBoardDisplay.h"



namespace catan
{
	PlayerItemBuildController::~PlayerItemBuildController(void)
	{
		mPlayerItemNode->remove();
		SafeDrop(mPlayerItemNode);
		SafeDrop(mPlayerItemCanBuildNodes);
		FOR_EACH(ISceneNodes, it, mAllBuildNodes)
		{
			(*it)->setVisible(false);
		}
		SafeDropAll(mAllBuildNodes);
	}

	bool PlayerItemBuildController::OnEvent( const SEvent& event )
	{
		if (event.EventType != EET_MOUSE_INPUT_EVENT)
			return false;

		switch(event.MouseInput.Event)
		{
		//case EMIE_LMOUSE_PRESSED_DOWN:
		//	MouseKeys[0] = true;
		//	break;
		//case EMIE_RMOUSE_PRESSED_DOWN:
		//	MouseKeys[2] = true;
		//	break;
		case EMIE_MOUSE_MOVED:
			OnMoveMove();
			return true;
		case EMIE_LMOUSE_PRESSED_DOWN:
			OnMoveLBtn();
			return true;
		}
		return false;
	}

	const core::vector3df PlayerItemBuildController::GetPosition( ISceneNode* checkSceneNode )
	{
		return checkSceneNode->getAbsolutePosition();
	}

	const core::vector3df PlayerItemBuildController::GetRotate( ISceneNode* checkSceneNode )
	{
		return checkSceneNode->getParent()->getRotation();
	}

// 	template <>
// 	static const tstring _FormatVar<core::vector3df(const tstring & str, const core::vector3df& x)
// 	{
// 		std::ostringstream ss;
// 		ss << str << "=" << (float)(x.X) << (float)(x.Y) << (float)(x.Z) << " ";
// 		return ss.str();
// 	}


	ISceneNode* PlayerItemBuildController::GetMouseCanBuildNode( core::line3df* ray /*= 0*/ )
	{
		core::line3df mouseRay = GetMouseRay();
		if (ray)
		{
			*ray = mouseRay;
		}
		//ray.end.Y = -ray.end.Y;
		core::vector3df intersection;
		// Used to show with triangle has been hit
		core::triangle3df hitTriangle;
		return mHelper->GetSceneManager()->getSceneCollisionManager()->getSceneNodeAndCollisionPointFromRay(mouseRay, intersection, hitTriangle, 0, mPlayerItemCanBuildNodes);
	}

	void PlayerItemBuildController::OnMoveMove()
	{
		core::line3df ray;
		ISceneNode* collNode = GetMouseCanBuildNode(&ray);
		if (collNode)
		{
			mPlayerItemNode->setPosition(GetPosition(collNode));
			mPlayerItemNode->setRotation(GetRotate(collNode));
			//collNode->setMaterialFlag(EMF_COLOR_MASK)
		}
		else
		{
			mPlayerItemNode->setPosition(GetMouseRay().end);
		}
	}

	void PlayerItemBuildController::OnMoveLBtn()
	{
		ISceneNode* collNode = GetMouseCanBuildNode();
		if (collNode)
		{
			VALID(mBuildHandler);
			Done(collNode->getParent()->getID());
		}
	}

	core::line3df PlayerItemBuildController::GetMouseRay()
	{
		core::position2df pos = mHelper->GetDevice()->getCursorControl()->getRelativePosition();
		core::vector3df v(2 * pos.X - 1.0f, -(2 * pos.Y - 1.0f), 1.0f);

		ICameraSceneNode* camera = mHelper->GetSceneManager()->getActiveCamera();
		const core::matrix4& matPrj = camera->getProjectionMatrix();
		const core::matrix4& matView = camera->getViewMatrix();
		v.X /= matPrj(0,0);
		v.Y /= matPrj(1,1);
		core::matrix4 invertMat;
		if (!matView.getInverse(invertMat))
		{
			LogError(_T("no view invermat"));
			return core::line3df();
		}

		core::vector3df vPickRayDir;
		vPickRayDir.X = v.X * invertMat(0,0)+ v.Y * invertMat(1,0) + v.Z * invertMat(2,0);
		vPickRayDir.Y = v.X * invertMat(0,1) + v.Y * invertMat(1,1) + v.Z * invertMat(2,1);
		vPickRayDir.Z = v.X * invertMat(0,2) + v.Y * invertMat(1,2) + v.Z * invertMat(2,2);

		core::vector3df vPickRayOrig;
		vPickRayOrig.X = invertMat(3,0);
		vPickRayOrig.Y = invertMat(3,1);
		vPickRayOrig.Z = invertMat(3,2);

		f32 r = (0.0f- vPickRayOrig.Y) / vPickRayDir.Y;

		return core::line3df(vPickRayOrig, vPickRayOrig + (vPickRayDir) * r);
		//ray.end.Y = -ray.end.Y;

	}

	class BuildingController : public PlayerItemBuildController
	{
	public:
		~BuildingController()
		{
			
		}
		virtual std::string GetPlayerItemBuildNodeName() {return "BuildPoints";}

		virtual void ShowCanBuild()
		{
			BuildPoints buildPoints = GetBuildPoints();
			if (buildPoints.empty())
			{
				LogError(_T("no point to build"));
				VALID(0);
				return ;
			}

			FOR_EACH(BuildPoints, it, buildPoints)
			{
				ISceneNode* buildPointNode = mHelper->GetSceneManager()->getSceneNodeFromId(it->Id(), mPlayerItemCanBuildNodes);
				buildPointNode->setVisible(true);
				buildPointNode->grab();
				mAllBuildNodes.push_back(buildPointNode);
				//meshNode->setMaterialFlag(video::EMF_COLOR_MASK)
			}
		}


		virtual ISceneNode* CreatePlayeyItemNode()
		{
			ISceneNode* ret = mHelper->AddAnimatioMeshNode(GetMeshFileName(), mHelper->GetBoardNode());

			video::ITexture* tex  = mHelper->GetDevice()->getVideoDriver()->getTexture(tstring(ModDirectory() + PlayerColor::ToString(mHelper->GetHostColor()) + _T(".png")).c_str());
			VALID(tex);
			ret->setName("TmpPlayerBuildItem");
			ret->setMaterialTexture(0, tex);
			VALID(ret);
			return ret;
		}

		virtual BuildPoints GetBuildPoints() = 0;
		virtual tstring GetMeshFileName() = 0;
	
	};
	
	class BuildHouseController : public BuildingController
	{
	public:
		virtual BuildPoints GetBuildPoints()
		{
			return mHelper->GetBoardLogic()->FindBuildHousePoints(mHelper->GetHostColor());
		}
		virtual tstring GetMeshFileName()
		{
			return (_T("./res/model/house.3ds"));
		}

		virtual void OnDone(int id)
		{
			mBuildHandler->OnBuildHouse(mHelper->GetBoard()->GetHandle<BuildPoint>(id));
		}
	};

	PlayerItemBuildController* PlayerItemBuildController::CreateBuildHouse(IHelperBase* helperbase)
	{
		return helperbase->New<BuildHouseController>();
	}

	class BuildSettlementController : public BuildingController
	{
	public:
		virtual BuildPoints GetBuildPoints()
		{
			return mHelper->GetBoardLogic()->FindBuildSettlementPoints(mHelper->GetHostColor());
		}

		virtual tstring GetMeshFileName()
		{
			return (_T("./res/model/settlement.3ds"));
		}

		virtual void OnDone(int id)
		{
			mBuildHandler->OnBuildSelement(mHelper->GetBoard()->GetHandle<BuildPoint>(id));
		}
	};

	
	PlayerItemBuildController* PlayerItemBuildController::CreateBuildSettlemnet(IHelperBase* helperbase)
	{
		return helperbase->New<BuildSettlementController>();
	}
	
	class BuildRoadController : public PlayerItemBuildController
	{
		virtual std::string GetPlayerItemBuildNodeName() {return "Edges";}
		virtual void ShowCanBuild()
		{
			Edges edges = GetEdges();
			if (edges.empty())
			{
				LogError(_T("no point to build"));
				VALID(0);
				return ;
			}

			FOR_EACH(Edges, it, edges)
			{
				ISceneNode* buildPointNode = mHelper->GetSceneManager()->getSceneNodeFromId(it->Id(), mPlayerItemCanBuildNodes);
				buildPointNode->setVisible(true);
				buildPointNode->grab();
				mAllBuildNodes.push_back(buildPointNode);
				//meshNode->setMaterialFlag(video::EMF_COLOR_MASK)
			}
		}


		virtual ISceneNode* CreatePlayeyItemNode()
		{
			ISceneNode* ret = mHelper->AddAnimatioMeshNode(GetMeshFileName(), mHelper->GetBoardNode());

			video::ITexture* tex  = mHelper->GetDevice()->getVideoDriver()->getTexture(tstring(ModDirectory() + PlayerColor::ToString(mHelper->GetHostColor()) + _T(".png")).c_str());
			VALID(tex);
			ret->setName("TmpPlayerBuildItem");
			ret->setMaterialTexture(0, tex);
			VALID(ret);
			return ret;
		}

		virtual Edges GetEdges()
		{
			return mHelper->GetBoardLogic()->FindAllBuildEdges(mHelper->GetHostColor());
			//return mHelper->GetBoardLogic()->Findbuiro(mHelper->GetHostColor());
		}

		virtual tstring GetMeshFileName()
		{
			return (_T("./res/model/road.3ds"));
		}

		virtual void OnDone(int id)
		{
			mBuildHandler->OnBuildRoad(mHelper->GetBoard()->GetHandle<Edge>(id));
		}

		
	};

	PlayerItemBuildController* PlayerItemBuildController::CreateBuildRoad(IHelperBase* helperbase)
	{
		return helperbase->New<BuildRoadController>();
	}



}

#include "CatanStratryTest.h"
void catan::PlayerItemBuildController::Test()
{
	CatanTest(OnItemBuild(*this));
}
